package heliotrope.utils.mission
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.ProgressEvent;
	
	public class MissionManager extends EventDispatcher
	{
		public static const MISSION_PROGRESS:String = "missionProgress";
		public static const TOTAL_PROGRESS:String = "totalProgress";
		
		private var _missionId:uint;
		private var _missionQueue:Vector.<Mission>;
		private var _currentMission:Mission;
		private var _isRunning:Boolean;
		private var _name:String;
		private var _totalWeight:Number;
		private var _finishedWeight:Number;
		public function MissionManager(name_:String = "")
		{
			_name = name_;
			
			_missionId = 0;
			_finishedWeight = 0;
			_totalWeight = 0;
			_isRunning = false;
			_missionQueue = new Vector.<Mission>;
		}
		
		public function addMission(mission_:Mission):void
		{
			mission_.id = _missionId++;
			_totalWeight += mission_.weight;
			_missionQueue.push(mission_);
		}
		
		public function run():void
		{
			_currentMission = _missionQueue.shift();
			if(_currentMission)
			{
				runMission(_currentMission);
				_isRunning = true;
			}
			else
			{
				dispatchEvent(new Event(Event.COMPLETE));
				_isRunning = false;
			}
		}
		
		private function runMission(mission_:Mission):void
		{
			_currentMission = mission_;
			var closure:Function = mission_.closure;
			var params:Array = mission_.params;
			if(mission_ is ListenedMission)
			{
				var mission:ListenedMission = mission_ as ListenedMission;
				var listener:IEventDispatcher = mission.listener;

				listener.addEventListener(mission.completeEvent, missionCompleteHandler);
				if(mission.progressEvent) listener.addEventListener(mission.progressEvent, missionProgressHandler);
				closure.apply(null, params);
			}
			else
			{
				closure.apply(null, params);
				missionCompleteHandler(null);
			}
		}
		
		protected function missionProgressHandler(event:ProgressEvent):void
		{
			var currentMissionProgress:ProgressEvent = new ProgressEvent(
				MissionManager.MISSION_PROGRESS, false, false, event.bytesLoaded, event.bytesTotal);
			dispatchEvent(currentMissionProgress);
			
			if(event.bytesTotal==0) return;
			var current:Number = event.bytesLoaded/event.bytesTotal * _currentMission.weight;
			var totalMissionProgress:ProgressEvent = new ProgressEvent(
				MissionManager.TOTAL_PROGRESS,false,false,_finishedWeight+current,_totalWeight);
			dispatchEvent(totalMissionProgress);
		}
		
		protected function missionCompleteHandler(event:Event):void
		{
			trace(this+" complete ["+_currentMission+']');
			
			if(_currentMission is ListenedMission)
			{
				var currentMission:ListenedMission = _currentMission as ListenedMission;
				currentMission.listener.removeEventListener(currentMission.completeEvent, missionCompleteHandler);
				if(currentMission.progressEvent) currentMission.listener.removeEventListener(
					currentMission.progressEvent, missionProgressHandler);
			}
			dispatchEvent(new Event(_currentMission.id+Event.COMPLETE));
			_finishedWeight += _currentMission.weight;
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _finishedWeight, _totalWeight));
			
			var nextMission:Mission = _missionQueue.shift();
			if(nextMission)
			{
				runMission(nextMission);
			}
			else
			{
				dispatchEvent(new Event(Event.COMPLETE));
				_isRunning = false;
			}
		}

		public function get name():String
		{
			return _name;
		}
		
		override public function toString():String
		{
			return "MissionManager["+_name+"]";
		}
		
	}
}